package com.changxianggu.cloud.edu.tool.core;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.setting.Setting;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.changxianggu.cloud.edu.tool.constant.HttpConstant;
import com.changxianggu.cloud.edu.tool.entity.*;
import com.changxianggu.cloud.edu.tool.entity.gen.GenCodeVO;
import com.changxianggu.cloud.edu.tool.entity.vo.*;
import com.changxianggu.cloud.edu.tool.key.*;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author liuyuantao
 */
@Slf4j
public class HandlerResultData {


    public void handlerSchoolData(List<Map<String, Object>> collegeList,
                                  List<Map<String, Object>> majorList,
                                  List<Map<String, Object>> officeList,
                                  List<Map<String, Object>> teacherList,
                                  List<Map<String, Object>> clazzList,
                                  List<Map<String, Object>> studentList,
                                  List<Map<String, Object>> courseList,
                                  List<Map<String, Object>> courseStudentList,
                                  String configPath, Integer schoolId, Integer batchId,
                                  GenCodeVO genCodeVO) {
        KeyProperty keyProperty = initConfig(configPath);
        if (keyProperty == null) {
            throw new RuntimeException("配置文件不存在");
        }
        Map<String, Object> collegeMap = MapUtil.newHashMap();
        Map<String, Object> majorMap = MapUtil.newHashMap();
        Map<String, Object> majorFxMap = MapUtil.newHashMap();
        Map<String, Object> officeMap = MapUtil.newHashMap();
        Map<String, Object> clazzMap = MapUtil.newHashMap();
        Map<String, Object> teacherMap = MapUtil.newHashMap();
        Map<String, Object> studentMap = MapUtil.newHashMap();
        Map<String, Object> courseMap = MapUtil.newHashMap();
        Map<String, Object> useCourseMap = MapUtil.newHashMap();
        List<CourseStudentVO> courseStudentVOList = new ArrayList<>();
        DataExtraCore dataHandlerUtil = new DataExtraCore(keyProperty);
        /////////////////////////////////////////////////////////
        log.debug("数据处理第2步开始:准备从平台获取已上线学校的数据!");
        if (schoolId > 0) {
            collegeMap = initCollegeData(HttpConstant.COLLEGE_URL, schoolId);
            majorMap = initMajorData(HttpConstant.MAJOR_URL, schoolId);
            majorFxMap = initMajorFxData(HttpConstant.MAJOR_FX_URL, schoolId);
            officeMap = initOfficeData(HttpConstant.OFFICE_URL, schoolId);
            teacherMap = initTeacherData(HttpConstant.TEACHER_URL, schoolId);
            clazzMap = initClazzData(HttpConstant.CLAZZ_URL, schoolId);
            useCourseMap = initCourseData(HttpConstant.BATCH_COURSE_URL, schoolId, batchId);
        } else {
            log.debug("需要处理的学校未上线,不需要从平台获取数据!");
        }
        log.debug("数据处理第2步结束!");
        ////////////////////////////////////////////////////////
        log.debug("数据处理第3步:准备从EXCEL里提取数据");
        //初始化学院数据
        log.debug("准备提取院系数据");
        collegeMap = dataHandlerUtil.extractCollegeData(collegeMap, collegeList, majorList, teacherList, clazzList, studentList, genCodeVO.getGenCollege());
        log.debug("提取院系数据结束!");
        //初始化专业数据
        log.debug("准备提取专业数据");
        majorMap = dataHandlerUtil.extractMajorData(majorMap, collegeMap, majorList, clazzList, studentList, genCodeVO.getGenMajor());
        log.debug("提取专业数据结束");
        String majorTypeMark = keyProperty.getMajorKeyProperty().getMajorTypeMark();
        if (StrUtil.isNotBlank(majorTypeMark)) {
            log.debug("准备提取专业方向数据");
            majorFxMap = dataHandlerUtil.extraFx4Major(majorMap, majorTypeMark, majorFxMap);
            log.debug("提取专业方向数据结束");
        }
        //初始化教研室数据
        if (CollUtil.isNotEmpty(officeList)) {
            log.debug("准备提取教研室数据");
            officeMap = dataHandlerUtil.extractOfficeData(officeMap, officeList, courseList, courseStudentList, collegeMap, genCodeVO.getGenOffice());
            log.debug("提取教研室数据结束");
        }
        //初始化班级数据
        log.debug("准备提取班级数据");
        clazzMap = dataHandlerUtil.extractClazzData(clazzMap, clazzList, studentList, majorMap, collegeMap, genCodeVO.getGenClazz());
        log.debug("提取班级数据结束");
        //初始化教师数据
        if (CollUtil.isNotEmpty(teacherList)) {
            log.debug("准备提取教师数据");
            teacherMap = dataHandlerUtil.extractTeacherData(teacherMap, teacherList, collegeMap);
            log.debug("提取教师数据结束");
        }
        //初始化学生数据
        if (CollUtil.isNotEmpty(studentList)) {
            log.debug("准备提取学生数据");
            studentMap = dataHandlerUtil.extractStudentData(studentList, collegeMap, majorMap, majorFxMap, clazzMap);
            log.debug("提取学生数据结束");
        }
        //这里需要初始化班级人数
        if (MapUtil.isNotEmpty(clazzMap) && MapUtil.isNotEmpty(studentMap)) {
            log.debug("准备重新初始化班级人数");
            clazzMap = dataHandlerUtil.resetClazzNum(clazzMap, studentMap);
            log.debug("初始化班级人数结束");
        }
        if (CollUtil.isNotEmpty(courseList)) {
            log.debug("准备提取班级上课数据");
            courseMap = dataHandlerUtil.extractCourseData(courseList, collegeMap, officeMap, teacherMap, clazzMap, majorMap, majorFxMap, useCourseMap);
            log.debug("提取班级上课数据结束");
        }
        if (CollUtil.isNotEmpty(courseStudentList)) {
            log.debug("准备提取学生选修课数据");
            courseStudentVOList = dataHandlerUtil.extractCourseStudentData(courseStudentList, collegeMap, officeMap, teacherMap, clazzMap, useCourseMap);
            log.debug("提取学生选修课数据结束");
        }
        List<String> errorList = dataHandlerUtil.getErrorList();
        log.debug("数据处理第3步结束!");
        /////////////////////////////////////////////////////
        log.debug("数据处理第4步:准备将处理的结果写入本地压缩包");
        write2Local(collegeMap, majorMap, majorFxMap, officeMap, clazzMap, studentMap, teacherMap, courseMap, courseStudentVOList, errorList, genCodeVO.getDownAll());
        log.debug("数据处理第4步结束!");
    }

    /**
     * 写出数据到本地
     *
     * @param collegeMap
     * @param majorMap
     * @param officeMap
     * @param studentMap
     * @param teacherMap
     * @param courseMap
     */
    private void write2Local(Map<String, Object> collegeMap,
                             Map<String, Object> majorMap,
                             Map<String, Object> majorFxMap,
                             Map<String, Object> officeMap,
                             Map<String, Object> clazzMap,
                             Map<String, Object> studentMap,
                             Map<String, Object> teacherMap,
                             Map<String, Object> courseMap,
                             List<CourseStudentVO> courseStudentVOList,
                             List<String> errorList,
                             boolean isDownAll) {
        // 获取系统临时目录
        String tmpdir = System.getProperty("java.io.tmpdir");
        String rootPath = tmpdir + File.separator + "changxianggu" + File.separator;
        FileUtil.del(rootPath);
        FileUtil.mkdir(rootPath);
        if (MapUtil.isNotEmpty(collegeMap)) {
            String collegeFullPath = rootPath + "院系表.xlsx";
            writeMapFile(collegeFullPath, collegeMap, CollegeVO.class, isDownAll);
        }
        if (MapUtil.isNotEmpty(majorMap)) {
            String majorFullPath = rootPath + "专业表.xlsx";
            writeMapFile(majorFullPath, majorMap, MajorVO.class, isDownAll);
        }
        if (MapUtil.isNotEmpty(majorFxMap)) {
            String majorFxFullPath = rootPath + "专业方向表.xlsx";
            writeMapFile(majorFxFullPath, majorFxMap, MajorFxVO.class, isDownAll);
        }
        if (MapUtil.isNotEmpty(officeMap)) {
            String officeFullPath = rootPath + "教研室表.xlsx";
            writeMapFile(officeFullPath, officeMap, OfficeVO.class, isDownAll);
        }
        if (MapUtil.isNotEmpty(courseMap)) {
            String courseFullPath = rootPath + "课程表.xlsx";
            writeMapFile(courseFullPath, courseMap, CourseVO.class, isDownAll);
        }
        if (CollUtil.isNotEmpty(courseStudentVOList)) {
            String courseFullPath = rootPath + "学生课程选修表.xlsx";
            writeListFile(courseFullPath, courseStudentVOList, CourseStudentVO.class, isDownAll);
        }
        if (MapUtil.isNotEmpty(studentMap)) {
            String studentFullPath = rootPath + "学生表.xlsx";
            writeMapFile(studentFullPath, studentMap, StudentVO.class, isDownAll);
        }
        if (MapUtil.isNotEmpty(teacherMap)) {
            String teacherFullPath = rootPath + "教师表.xlsx";
            writeMapFile(teacherFullPath, teacherMap, TeacherVO.class, isDownAll);

        }
        if (MapUtil.isNotEmpty(clazzMap)) {
            String clazzFullPath = rootPath + "班级表.xlsx";
            writeMapFile(clazzFullPath, clazzMap, ClazzVO.class, isDownAll);
        }
        if (CollUtil.isNotEmpty(errorList)) {
            String errorFullPath = rootPath + "错误信息汇总.xlsx";
            Map<String, Object> errorMap = new HashMap<>();
            for (String str : errorList) {
                ErrorVO errorVO = new ErrorVO();
                errorVO.setErrorMessage(str);
                errorMap.put(str, errorVO);
            }
            writeMapFile(errorFullPath, errorMap, ErrorVO.class, isDownAll);
        }
    }

    /**
     * 将Map数据转换成lsit写入xlsx中
     *
     * @param fullPath
     * @param dataMap
     * @param clazz
     */
    private void writeMapFile(String fullPath, Map<String, Object> dataMap, Class<? extends BaseWriteExcelModel> clazz, boolean isDownAll) {
        List<BaseWriteExcelModel> tmpCourseList = new ArrayList<>();
        for (Object obj : dataMap.values()) {
            BaseWriteExcelModel cast = clazz.cast(obj);
            Integer platformData = cast.getPlatformData();
            if (isDownAll) {
                //需要下载平台数据
                tmpCourseList.add(cast);
            } else {
                //不需要下载平台数据
                if (platformData != null && platformData == 0) {
                    tmpCourseList.add(cast);
                }
            }
        }
        writeListFile(fullPath, tmpCourseList, clazz, isDownAll);
    }

    /**
     * 将数据写入xlsx中
     *
     * @param fullPath
     * @param dataList
     * @param clazz
     */
    private void writeListFile(String fullPath, List<? extends BaseWriteExcelModel> dataList, Class<? extends BaseWriteExcelModel> clazz, boolean isDownAll) {

        OutputStream out = null;

        try {
            //创建临时文件
            File tmpFile = new File(fullPath);
            out = new FileOutputStream(tmpFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        ExcelWriter writer = EasyExcelFactory.getWriter(out, ExcelTypeEnum.XLSX, true);
        //写第一个sheet, sheet1  数据全是List<String> 无模型映射关系
        Sheet sheet = new Sheet(1, 1, clazz);
        //or 设置自适应宽度
        sheet.setAutoWidth(Boolean.TRUE);
        writer.write(dataList, sheet);
        writer.finish();
        dataList.clear();
        try {
            if (out != null) {
                out.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化配置数据
     * 将配置文件的内容读取成POJO对象
     *
     * @return
     */
    private KeyProperty initConfig(String configPath) {
        KeyProperty keyProperty = new KeyProperty();
        if (!FileUtil.exist(configPath)) {
            return keyProperty;
        }
        File file = FileUtil.file(configPath);
        Setting setting = new Setting(file, CharsetUtil.CHARSET_UTF_8, true);
        String schoolId = setting.get("schoolId");
        keyProperty.setSchoolId(schoolId);
        Map<String, String> college = setting.getMap("college");
        Map<String, String> major = setting.getMap("major");
        Map<String, String> office = setting.getMap("office");
        Map<String, String> clazz = setting.getMap("clazz");
        Map<String, String> student = setting.getMap("student");
        Map<String, String> teacher = setting.getMap("teacher");
        Map<String, String> course = setting.getMap("course");
        Map<String, String> courseStudent = setting.getMap("courseStudent");
        keyProperty.setCollegeKeyProperty(BeanUtil.mapToBean(college, CollegeKeyProperty.class, true));
        keyProperty.setMajorKeyProperty(BeanUtil.mapToBean(major, MajorKeyProperty.class, true));
        keyProperty.setOfficeKeyProperty(BeanUtil.mapToBean(office, OfficeKeyProperty.class, true));
        keyProperty.setClazzKeyProperty(BeanUtil.mapToBean(clazz, ClazzKeyProperty.class, true));
        keyProperty.setTeacherKeyProperty(BeanUtil.mapToBean(teacher, TeacherKeyProperty.class, true));
        keyProperty.setStudentKeyProperty(BeanUtil.mapToBean(student, StudentKeyProperty.class, true));
        keyProperty.setCourseKeyProperty(BeanUtil.mapToBean(course, CourseKeyProperty.class, true));
        keyProperty.setCourseStudentKeyProperty(BeanUtil.mapToBean(courseStudent, CourseStudentKeyProperty.class, true));
        return keyProperty;
    }

    /**
     * 根据指定的url获取数据
     *
     * @param url
     * @param schoolId
     * @return
     */
    private JSONArray fetchDBData(String url, Integer schoolId) {
        HttpResponse execute = HttpRequest.get(url).form("schoolId", schoolId).execute();
        JSONObject jsonData = JSONObject.parseObject(execute.body());
        return jsonData.getJSONArray("data");
    }

    /**
     * 根据指定的url获取数据
     *
     * @param url
     * @param schoolId
     * @return
     */
    private JSONArray fetchCourseDBData(String url, Integer schoolId, Integer batchId) {
        HttpResponse execute = HttpRequest.get(url).form("schoolId", schoolId).form("batchId", batchId).execute();
        JSONObject jsonData = JSONObject.parseObject(execute.body());
        return jsonData.getJSONArray("data");
    }

    /**
     * 初始化院系数据
     *
     * @param url
     * @param schoolId
     * @return
     */
    private Map<String, Object> initCollegeData(String url, Integer schoolId) {
        Map<String, Object> resultMap = new HashMap<>(32);
        JSONArray jsonArrayData = fetchDBData(url, schoolId);
        List<CollegeVO> collegeVOList = jsonArrayData.toJavaList(CollegeVO.class);
        for (CollegeVO collegeVO : collegeVOList) {
            String code = collegeVO.getCode();
            resultMap.put(code, collegeVO);
        }
        return resultMap;
    }

    /**
     * 初始化专业数据
     *
     * @param url
     * @param schoolId
     * @return
     */
    private Map<String, Object> initMajorData(String url, Integer schoolId) {
        Map<String, Object> resultMap = new HashMap<>(32);
        JSONArray jsonArrayData = fetchDBData(url, schoolId);
        List<MajorVO> collegeVOList = jsonArrayData.toJavaList(MajorVO.class);
        for (MajorVO majorVO : collegeVOList) {
            String code = majorVO.getCode();
            resultMap.put(code, majorVO);
        }
        return resultMap;
    }

    /**
     * 初始化专业方向数据
     *
     * @param url
     * @param schoolId
     * @return
     */
    private Map<String, Object> initMajorFxData(String url, Integer schoolId) {
        Map<String, Object> resultMap = new HashMap<>(32);
        JSONArray jsonArrayData = fetchDBData(url, schoolId);
        List<MajorFxVO> collegeVOList = jsonArrayData.toJavaList(MajorFxVO.class);
        for (MajorFxVO majorFxVO : collegeVOList) {
            String code = majorFxVO.getCode();
            resultMap.put(code, majorFxVO);
        }
        return resultMap;
    }

    /**
     * 初始化教研室数据
     *
     * @param url
     * @param schoolId
     * @return
     */
    private Map<String, Object> initOfficeData(String url, Integer schoolId) {
        Map<String, Object> resultMap = new HashMap<>(32);
        JSONArray jsonArrayData = fetchDBData(url, schoolId);
        List<OfficeVO> collegeVOList = jsonArrayData.toJavaList(OfficeVO.class);
        for (OfficeVO officeVO : collegeVOList) {
            String code = officeVO.getCode();
            resultMap.put(code, officeVO);
        }
        return resultMap;
    }

    /**
     * 初始化教师数据
     *
     * @param url
     * @param schoolId
     * @return
     */
    private Map<String, Object> initTeacherData(String url, Integer schoolId) {
        Map<String, Object> resultMap = new HashMap<>(32);
        JSONArray jsonArrayData = fetchDBData(url, schoolId);
        List<TeacherVO> collegeVOList = jsonArrayData.toJavaList(TeacherVO.class);
        for (TeacherVO teacherVO : collegeVOList) {
            String code = teacherVO.getCode();
            resultMap.put(code, teacherVO);
        }
        return resultMap;
    }

    /**
     * 初始化班级数据
     *
     * @param url
     * @param schoolId
     * @return
     */
    private Map<String, Object> initClazzData(String url, Integer schoolId) {
        Map<String, Object> resultMap = new HashMap<>(32);
        JSONArray jsonArrayData = fetchDBData(url, schoolId);
        List<ClazzVO> clazzVOList = jsonArrayData.toJavaList(ClazzVO.class);
        for (ClazzVO clazzVO : clazzVOList) {
            String code = clazzVO.getCode();
            resultMap.put(code, clazzVO);
        }
        return resultMap;
    }

    private Map<String, Object> initCourseData(String batchCourseUrl, Integer schoolId, Integer batchId) {
        Map<String, Object> resultMap = new HashMap<>(32);
        JSONArray jsonArrayData = fetchCourseDBData(batchCourseUrl, schoolId, batchId);
        List<CourseVO> courseVOList = jsonArrayData.toJavaList(CourseVO.class);
        for (CourseVO courseVO : courseVOList) {
            String code = courseVO.getCode();
            resultMap.put(code, courseVO);
        }
        return resultMap;
    }

}
